import glob , time , random

import FCVector

from maya import cmds
from AntsCrowd import Terrain , Simulator , Define
from AntsCrowd import playblast as pb

reload(Terrain)
reload(Simulator)
reload(pb)


class Scene:
    '''
    -----------------------------------------------
    How to use Scene Class
    
    import AntsCrowd.Scene as Scene
    reload(Scene)

    _scene = Scene.Scene()
    _scene.run( antCount = 10 )
    -----------------------------------------------
    '''
    def __init__( self ):
        self.terrainHeight = 0
        self.terrainScale = 10
        self.terrainCheck = 1
        self.antLod = 0
        self.antLowCount = 100
        self.antMiddleCount = 100
        self.antHighCount = 0
        self.antState = 'goal'
        self.timeMax = 168
        self.timeInterval = 1
        self.fps = 24 
        self.playblast = 0
        self.loddist = [2000,6000,11000]        
        self.arrangeCube = 0
        
        random.seed()

        self.simulator = Simulator.Simulator()        
        Terrain.Terrain()
        
    def run( self ):

        '''
        -----------------------------------------------
        Parameter Description
        
        terrainScale(float) : terrain subdivision count
        - unsigned float
        
        terrainHeight(bool) : plane or terrain
        - 1: Terrain or 0: Plane
        
        terrainCheck(bool) : select height process
        - 1: RayIntersection, 0: HeightMap
        
        antLod(bool) : create ants used level of distance
        - True: use lod, False: create each level ant
        
        antCount(int) : number of low level ants
        - unsigned number
        
        antMiddleCount(int) : number of middle level ants
        - unsigned number
        
        antHighCount(int) : number of high level ants
        - unsigned number
        
        antState(string) : select ant state
        - 'wander', 'goal'
        
        timeMax(int) : total frame of scene
        - unsigned number
        
        timeInterval(int) : keyframe interval
        - 1 ~ timeMax
        
        playblast(bool) : run playblast after scene simulate
        - 1(Yes) or 0(No)       
        
        loddist(int, int, int) : Far Near Endline lod distance
        
        arrangeCube(bool) : custom ant arrange mode
        - 1(Yes) or 0(No) 
        -----------------------------------------------
        '''

        # New Scene (clear previous scene)
        cmds.file( mf = False)
        cmds.file( f = True, new = True )
        
        Define.loddist = self.loddist
        
        Define.arrangeCubeMode = self.arrangeCube
        self.startTimer()
        
        self.importFile()        
            
        #self.initializeArrangeCube()
        self.initializeLayer()
        self.initializeScene()
        #self.initializeShader()
        self.processScene()
        
        self.endTimer()
        
        ## set MAYA up
        cmds.setAttr( "perspShape.farClipPlane" , 1000000 )
        cmds.workspace( cr =  r'X:\Works\3d\ant\antProject' )
        cmds.workspace( r'X:\Works\3d\ant\antProject' , o = 1 )
        cmds.DisplayShaded()
        cmds.modelEditor( cmds.getPanel( wf=1 ), e=1, ikHandles = 0 ,
                         joints = 0, nurbsCurves = 0 )
            
        antTotalCount = str( self.antLowCount+self.antMiddleCount+self.antHighCount )        
        filelist = glob.glob(r'X:\Works\3d\ant\antProject\scenes\\antCrowd_'+ antTotalCount +'_*.m*')
        sceneVer = '01' if filelist == [] else eval( filelist[-1].split('_')[-1].split('.')[0] )+1        
        cmds.file( rename = 'antCrowd_' + antTotalCount + '_' + str(sceneVer).zfill(2) + '.ma' )
        
        if self.playblast:
            pb.pb()
            
    def run1(self):
        # New Scene (clear previous scene)
        cmds.file( mf = False)
        cmds.file( f = True, new = True )         
        
        self.importFile()
    
    def run2(self):
        self.startTimer()
        self.initializeArrangeCube()
        self.initializeLayer()
        self.initializeScene()
        
        #self.initializeShader()
        self.processScene()
        
        self.endTimer()
        
        ## set MAYA up
        cmds.setAttr( "perspShape.farClipPlane" , 1000000 )
        cmds.workspace( cr =  r'X:\Works\3d\ant\antProject' )
        cmds.workspace( r'X:\Works\3d\ant\antProject' , o = 1 )
        cmds.DisplayShaded()
        cmds.modelEditor( cmds.getPanel( wf=1 ), e=1, ikHandles = 0 ,\
                         joints = 0, nurbsCurves = 0 )
            
        antTotalCount = str( self.antLowCount+self.antMiddleCount+self.antHighCount )        
        filelist = glob.glob(r'X:\Works\3d\ant\antProject\scenes\\antCrowd_'+ antTotalCount +'_*.m*')
        sceneVer = '01' if filelist == [] else eval( filelist[-1].split('_')[-1].split('.')[0] )+1        
        cmds.file( rename = 'antCrowd_' + antTotalCount + '_' + str(sceneVer).zfill(2) + '.ma' )
        
        if self.playblast:
            pb.pb() 
         
    def importFile( self ):
        #import Background
        if 0 == self.terrainHeight:       
            _bg = glob.glob( r"X:\Works\3d\ant\antProject\scenes\BG\antsCrowd_bg_01_kozz_*.mb" )[-1]
            cmds.file( _bg, o = True )
            
        # import all model file
        _low = glob.glob( r"X:\Works\3d\ant\model\Ants_low_*.mb" )[-1]
        _middle = glob.glob( r"X:\Works\3d\ant\model\Ants_mid_*.mb" )[-1]
        _high = glob.glob( r"X:\Works\3d\ant\rig\newant_ac_rig_*.mb" )[-1]
        
        cmds.file( _low, i = True, ra = False )
        cmds.file( _middle, i = True, ra = False )
        cmds.file( _high, i = True, ra = False )
        
        ## import camera
        #if self.terrainScale < 50 :
        #    cmds.file( r"X:\Works\3d\ant\cam\antCrowd_20_grd.mb", i = True, ra = False )
        #elif (50 <= self.terrainScale) and (self.terrainScale < 100):
        #    cmds.file( r"X:\Works\3d\ant\cam\antCrowd_50_grd.mb", i = True, ra = False )
        #else :
        #    cmds.file( r"X:\Works\3d\ant\cam\antCrowd_100_grd.mb", i = True, ra = False )
            
    def initializeShader( self ):
        _blinn = cmds.shadingNode( 'blinn',asShader=1 , n = 'antsCrowd_blinn' )
        _ramp = cmds.shadingNode( 'ramp',asTexture=1 , n = 'antsCrowd_rmp' )
        _shader = cmds.shadingNode( 'singleShadingSwitch', asUtility=1 , n='antsCrowd_singleSwitch' )

        cmds.removeMultiInstance( _ramp + '.colorEntryList[1]',b=1)
        cmds.setAttr( _ramp + ".colorEntryList[1].color" ,  0.0312047 , 0.0495308 , 0.153841 ) # blue
        cmds.setAttr( _ramp + ".colorEntryList[0].color" ,  0.185 ,0 ,0 )
        cmds.setAttr( _ramp + ".colorEntryList[1].position" , 1 )

        cmds.connectAttr( _ramp + '.outColor', _blinn + '.color' )
        cmds.connectAttr( _shader + '.out', _ramp + '.uvCoord.vCoord' )
        
        _shapeList = cmds.ls( 'ant_mid_*', type = 'mesh' )
        _behaviorList = cmds.ls( 'ant_behavior*' )
        
        try:
            cmds.sets( _blinn + 'SG', q = 1 )
        except:
            cmds.sets( cmds.ls('ant_behavior*'), r=1, nss=1, em=1, n=_blinn + 'SG' )    
            cmds.connectAttr( _blinn + '.outColor', _blinn + 'SG.surfaceShader', f=1 )
            
        cmds.sets( cmds.ls('ant_behavior*'), e=1, fe=_blinn + 'SG' )
        #cmds.hyperShade( _shapeList , assign = _blinn )

        for _shape in _behaviorList:
            tempList = []
            for i,x in enumerate( cmds.listRelatives( _shape , c=1 , ad=1 , type='mesh' ) ):
                if 'hi' in x :
                    if 'eye' in  x or 'leg' in x or 'body' in  x :
                        if 'Shape' in x:
                                x = x.replace('Shape' , '')
                        if 'Orig' in x:
                                x = x.replace('Orig' , '')
                        try :
                            cmds.connectAttr( x + '.instObjGroups[0]', _shader + '.input['+str(i)+'].inShape' )
                        except :
                            pass

        for _idx, _shape in enumerate(_shapeList):
            cmds.connectAttr( _shape + '.instObjGroups[0]', _shader + '.input['+str(_idx)+'].inShape' )

        for _idx, _behavior in enumerate(_behaviorList):
            cmds.addAttr( _behavior, ln = 'vcoord', at = 'float', min = 0, max = 1 )
            cmds.setAttr( _behavior + '.vcoord', e = 1, keyable = 1 )
            cmds.connectAttr( _behavior + '.vcoord', _shader + '.input['+str(_idx)+'].inSingle', f = 1 )
            cmds.setAttr( _behavior + '.vcoord', random.uniform( 0, 1.0 ) )

    def initializeScene( self ):
        if self.terrainHeight:            
            Terrain.Terrain.instance.createTerrain( r"\\192.168.131.222\kali\Project\AntsCrowd\Resource\heightmap.jpg", self.terrainScale )
        else:
            Terrain.Terrain.instance.createTerrain( None, self.terrainScale  )

        if self.antLod:
            for idx in xrange(self.antLowCount):
                if 'wander' == self.antState:
                    _position = Terrain.Terrain.instance.getRandPos()
                    _agent = self.simulator.fnAddAgent( _position.x, _position.y, 20, True )
                elif 'goal' == self.antState:
                    _position = Terrain.Terrain.instance.getPiePos()
                    _agent = self.simulator.fnAddAgent( _position.x, _position.y, 20, True )
                    _goal = Terrain.Terrain.instance.getGoalPos()
                    _agent.setGoal( _goal.x, _goal.y )
        else:
            for idx in xrange(self.antLowCount):            
                if Define.arrangeCubeMode :
                    _position = Terrain.Terrain.instance.getRandPosQuallityCube( 'low' )    
                else: 
                    _position = Terrain.Terrain.instance.getRandPosQuallity( 'low' )
                _agent = self.simulator.fnAddAgent( _position.x, _position.y, 20, _quality = 'low' )
                if 'goal' == self.antState:
                    _goal = Terrain.Terrain.instance.getGoalPos()
                    _agent.setGoal( _goal.x, _goal.y )

            for idx in xrange(self.antMiddleCount):
                if Define.arrangeCubeMode :
                    _position = Terrain.Terrain.instance.getRandPosQuallityCube( 'middle' )    
                else: 
                    _position = Terrain.Terrain.instance.getRandPosQuallity( 'middle' )
                _agent = self.simulator.fnAddAgent( _position.x, _position.y, 20, _quality = 'middle' )
                if 'goal' == self.antState:
                    _goal = Terrain.Terrain.instance.getGoalPos()
                    _agent.setGoal( _goal.x, _goal.y )

            for idx in xrange(self.antHighCount):
                if Define.arrangeCubeMode :
                    _position = Terrain.Terrain.instance.getRandPosQuallityCube( 'high' )    
                else: 
                    _position = Terrain.Terrain.instance.getRandPosQuallity( 'high' )
                _agent = self.simulator.fnAddAgent( _position.x, _position.y, 20, _quality = 'high' )
                if 'goal' == self.antState:
                    _goal = Terrain.Terrain.instance.getGoalPos()
                    _agent.setGoal( _goal.x, _goal.y )
    
    def initializeLayer(self):
        cmds.createDisplayLayer (name =  "antLow",  empty=1)
        cmds.createDisplayLayer (name =  "antMiddle",  empty=1)
        cmds.createDisplayLayer (name =  "antHigh",  empty=1)
    
    def processScene( self ):
        cmds.playbackOptions( maxTime = self.timeMax )
        cmds.playbackOptions( minTime = 0 )

        for idx in xrange( self.timeMax + 1 ):
            #cmds.currentTime( idx )
            self.simulator.frameCount = idx
            self.simulator.preferredVelocities( 1.0 / self.fps )
            self.simulator.fnDoStep( 1.0 / self.fps, self.terrainCheck )
            
            print idx, 'frame'

    def initializeArrangeCube(self):
        lowbound=cmds.xform( 'antLowCube' , bb = 1 , q = 1 )  
        lowmin = FCVector.vector2D(lowbound[0],lowbound[2])
        lowmax = FCVector.vector2D(lowbound[3],lowbound[5])
        lowtrans = cmds.getAttr('antLowCube.t')[0]
        vlow = FCVector.vector2D(lowtrans[0] , lowtrans[2])
        
        middlebound=cmds.xform( 'antMiddleCube' , bb = 1 , q = 1 )  
        middlemin = FCVector.vector2D(middlebound[0],middlebound[2])
        middlemax = FCVector.vector2D(middlebound[3],middlebound[5])
        middletrans = cmds.getAttr('antMiddleCube.t')[0]
        vmiddle = FCVector.vector2D(middletrans[0] , middletrans[2])
        
        
        highbound=cmds.xform( 'antHighCube' , bb = 1 , q = 1 )  
        highmin = FCVector.vector2D(highbound[0],highbound[2])
        highmax = FCVector.vector2D(highbound[3],highbound[5])
        hightrans = cmds.getAttr('antHighCube.t')[0]
        vhigh = FCVector.vector2D(hightrans[0] , hightrans[2])
        
        Define.arrangecube[0][0] = lowmin
        Define.arrangecube[0][1] = lowmax
        Define.arrangecube[0][2] = vlow
        Define.arrangecube[1][0] = middlemin
        Define.arrangecube[1][1] = middlemax
        Define.arrangecube[1][2] = vmiddle
        Define.arrangecube[2][0] = highmin
        Define.arrangecube[2][1] = highmax
        Define.arrangecube[2][2] = vhigh  
        
        print lowmin, lowmax, vlow
          
        
        
        
            
    def startTimer( self ):
        try :
            cmds.timer( s=True ,lap=1,name= 'tester' )
        except :
            cmds.timer( e=True ,name= 'tester')
            cmds.timer( s=True ,lap=1,name= 'tester' )
        print '\n\nProcess start\n', time.ctime()

    def endTimer( self ):
        processtime = cmds.timer( e=True ,name= 'tester')
        print "Process Completed: " , processtime / 60 , 'min'
        
    